package main

import (
	"fmt"
	"time"
)

// 协程池（Pool）结构体
type Pool struct {
	work chan func()   // 任务
	sem  chan struct{} // 协程池的大小，即同时执行的协程数量
}

// 创建协程池,包含 size 个协程
// work 是一个无缓冲通道
// sem  是一个缓冲通道，size大小即协程池大小（sem通道的缓冲大小）
func New(size int) *Pool {
	return &Pool{
		work: make(chan func()),
		sem:  make(chan struct{}, size),
	}
}

// 往协程池中添加任务
// 若设置协程池的大小为 2 ，当前两个任务进入协程池时，p.work是无缓冲通道，在其他协程中没有接收时无法写入，
// 所以不可能执行 case p.work <- task，会执行 case p.sem <- struct{}{}，发起一个协程，协程中会接收 p.work 通道的值，
// 这时 case p.work <- task 便可以执行。当 case p.sem <- struct{}{} 执行2次后，达到 sem 通道的最大缓冲数，不会再运行
// case p.sem <- struct{}{}。

func (p *Pool) NewTask(task func()) {
	select {
	case p.work <- task:
		fmt.Println("NewTask --> task")
	case p.sem <- struct{}{}:
		fmt.Println("NewTask --> sem")
		go p.worker(task)
	}
}

// 用于执行任务
func (p *Pool) worker(task func()) {
	defer func() { <-p.sem }()
	for {
		task()
		task = <-p.work
	}
}

func main() {
	pool := New(2)
	for i := 0; i < 100; i++ {
		pool.NewTask(func() {
			// fmt.Println("run task")
			time.Sleep(2 * time.Second)
			fmt.Println(time.Now())
		})
	}

	time.Sleep(50 * time.Second)
	fmt.Println("程序结束")

}
